package main

import (
	"context"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"time"
)

var videoChan = make(chan Video, 200)
var c = make(chan int)

type VideoMaker struct {
	dirname string
}

func PathExists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return false
}

func (vm *VideoMaker) getFiles() {
	dir, _ := ioutil.ReadDir(vm.dirname)
	pthSep := string(os.PathSeparator)
	log.Println(pthSep)
	for _, f := range dir {
		if f.IsDir() {
			authorID := f.Name()
			childDir, _ := ioutil.ReadDir(vm.dirname + pthSep + f.Name())
			makeDir := vm.dirname + pthSep + f.Name() + pthSep + "maked"
			if PathExists(makeDir) == false {
				log.Println(makeDir)
				os.Mkdir(makeDir, os.ModePerm)
			}
			for _, childF := range childDir {
				if childF.IsDir() {
					continue
				}

				var v = Video{}
				if db.Where("author_id = ?", authorID).Where("title = ?", childF.Name()).First(&v).RecordNotFound() == false {
					if v.Status == TaskUnStart || v.Status == TaskRunning {
						if PathExists(v.Target) {
							os.Remove(v.Target)
						}
						videoChan <- v
					}
					continue
				}

				v.AuthorID = authorID
				v.Status = TaskUnStart
				v.Origin = vm.dirname + pthSep + f.Name() + pthSep + childF.Name()
				v.Title = childF.Name()
				v.Target = makeDir + pthSep + childF.Name()
				db.Create(&v)

				if PathExists(v.Target) {
					os.Remove(v.Target)
				}
				videoChan <- v
			}
		}
	}
}

func (vm *VideoMaker) runCommandWithTimeout(c string, timeout time.Duration, arg ...string) error {
	ctx, _ := context.WithTimeout(context.Background(), timeout)
	cmd := exec.CommandContext(ctx, c, arg...)

	cmd.Start()
	return cmd.Wait()
}

func (vm *VideoMaker) runFfmpeg() {
	log.Println("ffmpeg")
	for {
		v := <-videoChan
		db.Model(&v).Update("status", TaskRunning)
		err := vm.runCommandWithTimeout("ffmpeg", 100*time.Second, "-accurate_seek", "-i", v.Origin, "-vf", "hflip", "-s", "1080*1920", "-strict", "-2", v.Target)
		if err != nil {
			db.Model(&v).Update("status", TaskFailed)
			continue
		}
		db.Model(&v).Update("status", TaskSuccess).Update("target", v.Target)
	}
}

func (vm *VideoMaker) initVideo() {
	for i := 0; i < 3; i++ {
		go vm.runFfmpeg()
	}
}

func main() {
	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		log.Fatal(err)
	}

	initDB()
	v := &VideoMaker{dirname: dir}
	v.initVideo()
	v.getFiles()
	<-c
}
